package top.zhangjianyong.blog.service.impl;

import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.SystemMessage;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import top.zhangjianyong.blog.ai.client.BlogVectorStoreClient;
import top.zhangjianyong.blog.ai.client.OpenAiClient;
import top.zhangjianyong.blog.ai.model.BlogData;
import top.zhangjianyong.blog.params.ai.ChatParam;
import top.zhangjianyong.blog.response.ApiResponse;
import top.zhangjianyong.blog.service.AIService;
import top.zhangjianyong.blog.service.BlogService;

/**
 * @author zhangjianyong
 * @since 2025/7/7 12:04
 */
@Slf4j
@Service
public class AIServiceImpl implements AIService {

  @Resource private OpenAiClient openAiClient;
  @Resource private BlogVectorStoreClient blogVectorStoreClient;
  @Lazy @Resource private BlogService blogService;

  // 针对1核2G服务器优化：限制搜索结果数量，避免内存溢出
  private static final int MAX_SEARCH_RESULTS = 3;
  // 针对1核2G服务器优化：限制知识库内容长度，避免超出模型上下文限制
  private static final int MAX_KNOWLEDGE_LENGTH = 20000;
  // 内存使用率阈值（80%），超过此阈值时拒绝处理
  private static final double MEMORY_THRESHOLD = 0.8;

  /**
   * 检查内存使用情况
   *
   * @return true 如果内存使用率超过阈值
   */
  private boolean isMemoryHigh() {
    try {
      MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
      long usedHeap = memoryBean.getHeapMemoryUsage().getUsed();
      long maxHeap = memoryBean.getHeapMemoryUsage().getMax();
      double memoryUsage = (double) usedHeap / maxHeap;

      log.info(
          "当前内存使用: {}/{} MB ({}%)", usedHeap / 1024 / 1024, maxHeap / 1024 / 1024, memoryUsage);

      return memoryUsage > MEMORY_THRESHOLD;
    } catch (Exception e) {
      log.warn("无法获取内存使用情况", e);
      return false;
    }
  }

  public Flux<String> chat(ChatParam param) {
    List<Message> list =
        param.getMessages().stream()
            .map(
                message ->
                    switch (message.getRole()) {
                      case "user" -> new UserMessage(message.getContent());
                      case "assistant" -> new AssistantMessage(message.getContent());
                      case "system" -> new SystemMessage(message.getContent());
                      default -> throw new IllegalArgumentException(
                          "Invalid role: " + message.getRole());
                    })
            .map(message -> (Message) message)
            .toList();
    return openAiClient.chat(list);
  }

  @Override
  public Flux<String> chatWithStore(ChatParam param) {
    try {
      // 检查内存使用情况
      if (isMemoryHigh()) {
        log.warn("内存使用率过高，拒绝处理请求");
        return Flux.just("抱歉，系统当前负载较高，请稍后重试。");
      }

      log.info("开始向量搜索，用户问题: {}", param.userMessage());

      // 搜索相关博客内容，限制结果数量
      List<BlogData> blogData = blogVectorStoreClient.searchBlogs(param.userMessage());

      // 限制搜索结果数量，避免内存溢出
      if (blogData.size() > MAX_SEARCH_RESULTS) {
        log.warn("搜索结果数量过多({})，限制为{}个", blogData.size(), MAX_SEARCH_RESULTS);
        blogData = blogData.subList(0, MAX_SEARCH_RESULTS);
      }

      // 构建知识库内容，限制长度
      String data = blogData.stream().map(BlogData::getText).collect(Collectors.joining("\n"));

      // 限制知识库内容长度
      if (data.length() > MAX_KNOWLEDGE_LENGTH) {
        log.warn("知识库内容过长({}字符)，截取前{}字符", data.length(), MAX_KNOWLEDGE_LENGTH);
        data = data.substring(0, MAX_KNOWLEDGE_LENGTH) + "...";
      }

      // 设置知识库内容
      if (StrUtil.isNotBlank(data)) {
        String systemMessage = "以下是与用户输入相关的知识资料：" + data;
        param.getMessages().add(new ChatParam.Message("system", systemMessage));
        log.info("添加知识库内容，长度: {}字符", systemMessage.length());
      } else {
        log.info("未找到相关知识库内容");
      }

      return chat(param);
    } catch (OutOfMemoryError e) {
      log.error("内存溢出错误，尝试清理内存并返回错误响应", e);
      // 建议手动触发GC
      System.gc();
      // 返回错误信息流
      return Flux.just("抱歉，系统内存不足，请稍后重试或联系管理员。");
    } catch (Exception e) {
      log.error("chatWithStore处理异常", e);
      return Flux.just("抱歉，处理您的请求时出现异常，请稍后重试。");
    }
  }

  @Override
  public ApiResponse buildBlogVectorStore() {
    try {
      // 检查内存使用情况
      if (isMemoryHigh()) {
        log.warn("内存使用率过高，拒绝构建向量库");
        return ApiResponse.fail("系统当前负载较高，请稍后重试");
      }

      List<BlogData> list =
          blogService.listPublished().stream()
              .map(
                  blog -> {
                    BlogData blogData = new BlogData();
                    blogData.setId(blog.getId().toString());
                    blogData.setText(
                        blog.getTitle() + "\n" + blog.getSummary() + "\n" + blog.getMkContent());
                    return blogData;
                  })
              .toList();
      // 异步保存向量库
      blogVectorStoreClient.saveBlogsToVectorStoreAsync(list);
      return ApiResponse.success();
    } catch (OutOfMemoryError e) {
      log.error("构建向量库时内存溢出", e);
      System.gc();
      return ApiResponse.fail("内存不足，无法构建向量库");
    } catch (Exception e) {
      log.error("构建向量库异常", e);
      return ApiResponse.fail("构建向量库失败");
    }
  }
}
